#include "thread.h"
#include <iostream>
#include <cstring>
#include <string>
#include <cerrno>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
using namespace ns_tp;

void Usage(char *proc)
{
    std::cout << "Usage\n\t" << proc << " server.port" << std::endl;
}

struct task
{

    task(int sock = 0)
        :_sock(sock){}
    void operator()()
    {
        while (true)
        {
            char from_client[1024] = {0};
            ssize_t size = read(_sock, from_client, sizeof(from_client));
            
            if (size > 0)
            {  
                from_client[size] = 0;
                std::string ret_message = from_client;
                std::cout << ret_message << std::endl;
                FILE *fp = popen(from_client, "r");
                char line[1024] = {0};
                while (fgets(line, sizeof(line), fp))
                {
                    ret_message += line;
                }
                pclose(fp);
                write(_sock, ret_message.c_str(), ret_message.size());
            }
            else if (size < 0)
            {
                std::cout << "read failed; replace" << std::endl;
            }
            else
            {
                std::cout << "client quit" << std::endl;
                break;
            }
        }
        close(_sock);
    }

private:
    int _sock;
};

void ServiceIO(int new_sock)
{
    while (true)
    {
        char from_client[1024] = {0};
        ssize_t size = read(new_sock, from_client, sizeof(from_client));
        std::cout << from_client;
        if (size > 0)
        {
            from_client[size] = 0;
            std::string ret_message = from_client;
            std::cout << ret_message << std::endl;
            FILE *fp = popen(from_client, "r");
            char line[1024] = {0};
            while (fgets(line, sizeof(line), fp))
            {
                ret_message += line;
            }
            pclose(fp);
            write(new_sock, ret_message.c_str(), ret_message.size());
        }
        else if (size < 0)
        {
            std::cout << "read failed; replace" << std::endl;
        }
        else
        {
            std::cout << "client quit" << std::endl;
            break;
        }
    }
}

void *service_run(void *psock)
{
    std::cout << "创建新线程成功" << std::cout;
    int sock = *(int *)psock;
    // delete (int*)psock;
    pthread_detach(pthread_self());
    ServiceIO(sock);
    close(sock);
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        return 0;
    }

    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0)
    {
        std::cerr << "socket failed" << errno << std::endl;
    }
    std::cout << "socket success" << std::endl;

    struct sockaddr_in local;
    memset(&local, 0, sizeof(local));
    local.sin_family = AF_INET;
    local.sin_port = htons(atoi(argv[1]));
    local.sin_addr.s_addr = INADDR_ANY;

    if (bind(sock, (struct sockaddr *)&local, sizeof(local)) < 0)
    {
        std::cerr << "bind failed" << errno << std::endl;
    }
    std::cout << "bind success" << std::endl;

    if (listen(sock, 5) < 0)
    {
        std::cerr << "listen failed" << errno << std::endl;
    }
    std::cout << "listen success" << std::endl;
    ThreadPool<task>* pool = ThreadPool<task>::Getsingle();
    pool->ThreadPoolInit();

    while (true)
    {
        struct sockaddr_in client;
        socklen_t len = sizeof(client);
        int new_sock = accept(sock, (struct sockaddr *)&client, &len);
        if (sock < 0)
        {
            std::cerr << "accept failed" << errno << std::endl;
            continue;
        }
        uint16_t cli_port = ntohs(client.sin_port);
        std::string cli_addr = inet_ntoa(client.sin_addr);
        std::cout << "get a client-> [" << cli_addr << ":" << cli_port << "], distributionb " << new_sock << std::endl;
        // int* psock = new int(new_sock);
        task t(new_sock);
        pool->Push(t); 
        //pthread_t tid;
        //pthread_create(&tid, nullptr, service_run, (void *)&new_sock);
    }
}
